#ifndef ALLOC_HPP
#define ALLOC_HPP

/*
空间分配器

STL 的分配器超级简化版本， 内存分配与回收 ， 目前不涉及到内存池的实现

*/

#include "construt.hpp"
#include "exceptdef.h"
#include <new>

// #define OPEN_ALLOC_DEBUG

#ifdef OPEN_ALLOC_DEBUG
#define ALLOC_DEBUG(memorySize) \
    TING_DEBUG("[allocator]: allocate memory size: %zd", memorySize)
#define DEALLOC_DEBUG(memorySize) \
    TING_DEBUG("[allocator]: deallocate memory size: %zd", memorySize)
#else
#define ALLOC_DEBUG(memorySize) ((void)0)
#define DEALLOC_DEBUG(memorySize) ((void)0)
#endif

namespace TingSTL {

template <typename Alloc, typename OtherType>
struct rebind_alloc {
    using type = typename Alloc::template rebind_alloc<OtherType>;
};

template <typename Alloc, typename OtherType>
using rebind_alloc_t = typename rebind_alloc<Alloc, OtherType>::type;

template <typename T>
struct allocator {
    // ////////////////////  类型定义 /////////////////////
    // 为了兼容后续内存池管理  存储一些元数据 重新定义一下类型别名
    using value_type = T;
    using pointer = T *;
    using const_pointer = const T *;
    using reference = T &;
    using const_reference = const T &;

    using size_type = size_t;
    using difference_type = ptrdiff_t;

    // rebind alloc 重新绑定其他类
    template <typename U>
    using rebind_alloc = allocator<U>;

    // ////////////////////  分配内存的基础方法 /////////////////////
    // 分配内存 不会调用构造器
    static T *allocate() {
        ALLOC_DEBUG(sizeof(T));
        return static_cast<T *>(::operator new(sizeof(T)));
    }

    static T *allocate(size_type n) {
        if (n == 0)
            return nullptr;
        ALLOC_DEBUG(sizeof(T) * n);
        return static_cast<T *>(::operator new(sizeof(T) * n));
    }

    // 取消内存分配
    static void deallocate(void *p) {
        if (p == nullptr)
            return;
        DEALLOC_DEBUG(sizeof(T));
        ::operator delete(p);
    }

    static void deallocate(void *p, size_type n) {
        if (p == nullptr)
            return;
        DEALLOC_DEBUG(sizeof(T) * n);
        ::operator delete(p);
    }

    // 在ptr 处构造对象
    static void construct(T *ptr) // 不带参数的
    {
        TING_ASSERT(ptr != nullptr, "nullptr cant  construct");
        TingSTL::construct(ptr);
    }

    template <typename... Args>
    static void construct(T *ptr, Args &&...args) // 带参数的
    {
        TingSTL::construct(ptr, std::forward<Args>(args)...);
    }

    //  在ptr处 析构对象
    static void destroy(T *p) {
        TingSTL::destroy(p);
    }

    static void destroy(T *first, T *last) {
        if (first != nullptr && last != nullptr)
            TingSTL::destroy(first, last);
    }
};

} // namespace TingSTL

#endif